import * as path from "path";
import { JsonDB } from "node-json-db";
import { Config } from "node-json-db/dist/lib/JsonDBConfig";
import { cloneDeep } from "lodash";
export type itemType = "childitem" | "commonitem" | "project" | "workspace";
export const rootId = "root";
export class DataSet<T extends { id: string }> {
  private _data: { [id: string]: T } = {};
  constructor(data: { [id: string]: T } | T[]) {
    if (Array.isArray(data)) {
      data.forEach((d) => this.set(d));
    } else {
      this._data = data;
    }
  }
  public set(item: T): void {
    this._data[item.id] = item;
  }
  public get(id: string): T | undefined {
    return this._data[id];
  }
  public toObject(): { [id: string]: T } {
    return cloneDeep(this._data);
  }
  public toArray() {
    return cloneDeep(Object.keys(this._data).map((key) => this._data[key]));
  }
}
export interface IBaseItem {
  itemType: itemType;
  id: string;
  title: string;
}
export interface IChildItem extends IBaseItem {
  parent: string;
  done: boolean;
}
export interface ICommonItem extends IBaseItem {
  parent: string;
  done: boolean;
  index: number;
  note?: string;
  childItemIds: string[];
}
export interface IProject extends IBaseItem {
  parent: string;
  note?: string;
  commonItemIds: string[];
}
export interface IWorkspace extends IBaseItem {
  parent: string;
  projectIds: string[];
}
export function getTableName(itemType: itemType) {
  return "/" + itemType;
}

class Database {
  private _db = new JsonDB(
    new Config(
      path.resolve(process.cwd(), "data/database.json"),
      true,
      true,
      "/"
    )
  );

  public get(dataPath: string): any {
    try {
      return this._db.getData(dataPath);
    } catch (err) {
      if (err.name === "DataError") {
        this._db.push(dataPath, {});
        return this.get(dataPath);
      }
      throw err;
    }
  }

  public set(dataPath: string, data: any) {
    this._db.push(dataPath, data);
  }
}
export const db = new Database();
